package com.neusoft.neuiotms.common.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.cache.caching.CacheService;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.common.converter.DictionaryConverter;
import com.neusoft.neuiotms.common.dto.DictionaryDTO;
import com.neusoft.neuiotms.common.model.Dictionary;
import com.neusoft.neuiotms.common.model.DictionaryType;
import com.neusoft.neuiotms.common.repository.DictionaryRepository;
import com.neusoft.neuiotms.common.repository.DictionaryTypeRepository;
import com.neusoft.neuiotms.common.service.DictionaryService;

@Service
public class DictionaryServiceImpl implements DictionaryService {

    @Autowired
    private DictionaryRepository dictionaryRepository;
    @Autowired
    private DictionaryConverter dictionaryConverter;
    @Autowired
    private DictionaryTypeRepository dictionaryTypeRepository;
    @Autowired
    private CacheService cacheService;

    @Value("${neuiotms.common.dictionay.cache.name:CACHE_COMMON_DIC}")
    public String CACHE_COMMON_DIC;

    @Override
    public List<DictionaryDTO> findAll(final Searchable searchable) {
        final List<Dictionary> models = this.dictionaryRepository.findAll(searchable);
        return this.dictionaryConverter.toListDTO(models);
    }

    @Override
    public Page<DictionaryDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<Dictionary> result = this.dictionaryRepository.search(pageable, searchable);
        return this.dictionaryConverter.toPageDTO(result);
    }

    @Override
    public DictionaryDTO create(final DictionaryDTO dto) {
        final Dictionary model = this.dictionaryConverter.toModel(dto);

        // 校验编码重复性
        final Dictionary check =
                this.dictionaryRepository.findByCodeAndDictionaryTypeType(dto.getCode(), dto.getType());
        if (check != null) {
            throw new UnitedException("字典编码不能重复", new Object[] {});
        }

        if (!StringUtils.isEmpty(dto.getType())) {
            try {
                final DictionaryType dictionaryType = this.dictionaryTypeRepository.findByType(dto.getType());
                model.setDictionaryType(dictionaryType);
            } catch (final EntityNotFoundException e) {
                throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {dto.getType() });
            }
        }
        this.dictionaryRepository.save(model);
        final DictionaryDTO result = this.dictionaryConverter.toDTO(model);

        // 刷新缓存
        this.putCache(result.getId(), false);

        return result;
    }

    @Override
    public DictionaryDTO update(final Long id, final DictionaryDTO dto) {

        Dictionary model;
        try {
            model = this.dictionaryRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        // 校验编码重复性
        final Dictionary check =
                this.dictionaryRepository.findByCodeAndDictionaryTypeType(dto.getCode(), dto.getType());
        if ((check != null) && (Long.valueOf(check.getId()) != Long.valueOf(id))) {
            throw new UnitedException("字典编码不能重复", new Object[] {});
        }

        dto.setId(model.getId());
        model = this.dictionaryConverter.toModel(dto);
        this.dictionaryRepository.save(model);

        final DictionaryDTO result = this.dictionaryConverter.toDTO(model);

        // 刷新缓存
        this.putCache(id, false);

        return result;
    }

    @Override
    public DictionaryDTO details(final Long id) {

        final Dictionary model;
        try {
            model = this.dictionaryRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        return this.dictionaryConverter.toDTO(model);
    }

    @Override
    public void delete(final Long id) {
        // 刷新缓存
        this.putCache(id, true);
        this.dictionaryRepository.deleteById(id);
    }

    @Override
    public List<DictionaryDTO> findByDictionaryType(final String type) {
        final DictionaryType dictionaryType = this.dictionaryTypeRepository.findByType(type);
        final List<Dictionary> models = this.dictionaryRepository.findByDictionaryType(dictionaryType);
        return this.dictionaryConverter.toListDTO(models);
    }

    @SuppressWarnings("unchecked")
    private void putCache(final Long id, final boolean isDelete) {

        final Dictionary model = this.dictionaryRepository.getOne(id);

        final String key = model.getDictionaryType().getType();

        List<DictionaryDTO> list = new ArrayList<>();
        List<DictionaryDTO> result = new ArrayList<>();

        if (this.cacheService.isInCache(this.CACHE_COMMON_DIC, key)) {

            list = this.cacheService.getSimpleObject(this.CACHE_COMMON_DIC,
                    key, List.class);

            result = list.stream().filter(k -> Long.valueOf(k.getId()) != Long.valueOf(id))
                    .collect(Collectors.toList());
        }

        if (!isDelete) {
            final DictionaryDTO dto = this.dictionaryConverter.toDTO(model);
            result.add(dto);
        }

        this.cacheService.remove(this.CACHE_COMMON_DIC, key);

        if ((result != null) && (result.size() > 0)) {
            this.cacheService.put(this.CACHE_COMMON_DIC, key, result);
        }

    }

    @Override
    public DictionaryDTO findByDictionaryTypeAndCode(final String type, final String code) {
        final Dictionary model = this.dictionaryRepository.findByCodeAndDictionaryTypeType(code, type);
        return this.dictionaryConverter.toDTO(model);
    }

    /**
     * {@link 根据code从缓存取数据}
     *
     * @param code 编码
     * @return List<DictionaryDTO>
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<DictionaryDTO> searchFromCache(final String type) {
        if (this.cacheService.isInCache(this.CACHE_COMMON_DIC, type)) {
            final List<DictionaryDTO> list = this.cacheService.getSimpleObject(this.CACHE_COMMON_DIC,
                    type, List.class);
            return list;
        } else {
            final List<Dictionary> list = this.dictionaryRepository.getByDictionaryType(type);
            if (CollectionUtils.isNotEmpty(list)) {
                final List<DictionaryDTO> result = new ArrayList<>();
                list.forEach(item -> {
                    result.add(this.dictionaryConverter.toDTO(item));
                });
                return result;
            }
            return null;
        }
    }

}
